//
// Copyright (C) 2008 Jackson Harper (jackson@ximian.com)

// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
//
//

using System;
using System.Data;
using System.Configuration;
using System.Collections.Generic;

using log4net;
using MySql.Data.MySqlClient;

namespace Grr.Models {
	
	public class Tag
	{
		private static readonly ILog log = LogManager.GetLogger(typeof(Tag));

		private long id;
		private string name;
		private long instances;

		public Tag (long id, string name, long instances)
		{
			this.id = id;
			this.name = name;
			this.instances = instances;
		}

		public long Id
		{
			get { return id; }
		}

		public string Name
		{
			get { return name; }
		}

		public long Instances
		{
			get { return instances; }
			set { instances = value; }
		}

		public static string UrlForTag(string tag)
		{
			return String.Concat("~/tags/", tag);
		}

		public static Tag Create(string name)
		{
			Tag tag = null;

			using (MySqlConnection rcon = DbContext.OpenReadWriteConnection())
			{
				MySqlCommand icmd = new MySqlCommand("INSERT INTO Tags (name) VALUES (?name)", rcon);
				icmd.Parameters.Add(new MySqlParameter("?name", MySqlDbType.VarChar, Validator.MaxTagNameLength)).Value = name;

				if (icmd.ExecuteNonQuery() != 1)
				{
					log.ErrorFormat("Unable to INSERT INTO Tags in Tag.Create name: '{0}'", name);
					return null;
				}

				MySqlCommand qcmd = new MySqlCommand("SELECT LAST_INSERT_ID()", rcon);

				tag = new Tag((long)qcmd.ExecuteScalar(), name, 0);

				icmd = new MySqlCommand("INSERT INTO tag_data (tag_id, count) VALUES (?tag_id, 1)", rcon);
				icmd.Parameters.Add (new MySqlParameter("?tag_id", MySqlDbType.Int64)).Value = tag.Id;

				icmd.ExecuteNonQuery ();
			}

			return tag;
		}

		public static Tag QueryForByName (string name)
		{
			using (MySqlConnection rcon = DbContext.OpenReadConnection())
			{
				MySqlCommand qcmd = new MySqlCommand("SELECT Tags.id, Tags.name, tag_data.count FROM Tags JOIN tag_data ON Tags.id = tag_data.tag_id WHERE Tags.name = ?name", rcon);
				qcmd.Parameters.Add(new MySqlParameter("?name", MySqlDbType.VarChar, Validator.MaxTagNameLength)).Value = name;
				MySqlDataReader reader = qcmd.ExecuteReader();

				if (!reader.Read())
					return null;
				
				return new Tag(reader.GetInt64 (0), reader.GetString(1), reader.GetInt64(2));
			}
		}

		public static List<Tag> GetTags ()
		{
			using (MySqlConnection rcon = DbContext.OpenReadConnection ()) {
				MySqlCommand qcmd = new MySqlCommand ("select Tags.id, Tags.name, tag_data.count FROM Tags JOIN tag_data ON Tags.id = tag_data.tag_id GROUP BY Tags.name ORDER BY Tags.name", rcon);

				MySqlDataReader reader = qcmd.ExecuteReader ();

				List<Tag> res = new List<Tag> ();
				while (reader.Read ()) {
					Tag t = new Tag (reader.GetInt64 (0), reader.GetString (1), reader.GetInt64 (2));
					if (t.Instances > 0)
						res.Add (t);
				}
				return res;
			}
		}

		public static SearchResult GetGrurrahsForTag(string tag, int max_results, int start_index)
		{
			List<SearchMatch> matches = new List<SearchMatch>();
			using (MySqlConnection con = DbContext.OpenReadConnection())
			{
				MySqlCommand cmd = new MySqlCommand("select Grurrahs.name, Tags.name, AVG(user_grurrah_ratings.rating) FROM Grurrahs " +
						"LEFT JOIN tag_map ON tag_map.grurrah_id = Grurrahs.id LEFT JOIN Tags ON Tags.id = tag_map.tag_id " +
						"LEFT JOIN user_grurrah_ratings ON user_grurrah_ratings.grurrah_id = Grurrahs.id " +
						"WHERE Tags.name = ?tag_name GROUP BY Grurrahs.name ORDER BY AVG(user_grurrah_ratings.rating) DESC LIMIT ?start_index,?max_results", con);
				cmd.Parameters.Add("?tag_name", MySqlDbType.VarChar, 100).Value = tag;
				cmd.Parameters.Add("?max_results", MySqlDbType.Int32).Value = max_results + 1;
				cmd.Parameters.Add("?start_index", MySqlDbType.Int32).Value = start_index;

				MySqlDataReader reader = cmd.ExecuteReader();
				while (reader.Read())
				{
					string name = reader.GetString("name");
					int rank = 0;
					if (reader [2] != DBNull.Value)
						rank = reader.GetInt32(2);
					
					SearchMatch match = new SearchMatch(name, String.Empty, String.Concat("~/grurrahs/", StringUtil.ToFriendlyUri (name)), rank);
					matches.Add(match);
				}

				bool more_available = matches.Count > max_results;
				if (more_available)
					matches.RemoveAt(max_results);

				return new SearchResult(matches, more_available);
			}
		}
	}
}
